package com.zjyd.douyangcommoncore.utils;

import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.Map;
import java.util.Objects;

/**
 * 精简版 RocketMQ 工具类（只保留常用功能，简单易用）
 * 核心能力：普通发送、延迟发送、顺序发送、异步发送、单向发送
 */
@Component
public class RocketMQSimpleHelper {

    // 底层 RocketMQ 模板（Spring 自动注入，需提前配置 application.yml）
    private final RocketMQTemplate rocketMQTemplate;

    @Autowired
    public RocketMQSimpleHelper(RocketMQTemplate rocketMQTemplate) {
        this.rocketMQTemplate = rocketMQTemplate;
    }

    // ============================ 同步发送（最常用，阻塞等待结果）============================

    /**
     * 普通同步发送（单条消息，默认超时时间：3秒）
     * @param topic 消息主题（必填，格式：topicName 或 topicName:tagName）
     * @param payload 消息内容（必填，支持任意序列化对象、字符串、字节数组）
     * @return 发送结果（包含 msgId、发送状态等）
     */
    public SendResult syncSend(String topic, Object payload) {
        return syncSend(topic, payload, null, 3000L);
    }

    /**
     * 普通同步发送（自定义超时时间）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param timeout 发送超时时间（毫秒，建议 1000-5000）
     * @return 发送结果
     */
    public SendResult syncSend(String topic, Object payload, long timeout) {
        return syncSend(topic, payload, null, timeout);
    }

    /**
     * 普通同步发送（带自定义消息头）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param headers 自定义消息头（可选，如：业务标识、优先级等）
     * @param timeout 发送超时时间（毫秒）
     * @return 发送结果
     */
    public SendResult syncSend(String topic, Object payload, Map<String, Object> headers, long timeout) {
        // 校验必填参数
        Assert.hasText(topic, "消息主题（topic）不能为空");
        Assert.notNull(payload, "消息内容（payload）不能为空");

        // 构建消息（支持自定义头）
        MessageBuilder<?> builder = MessageBuilder.withPayload(payload);
        if (Objects.nonNull(headers) && !headers.isEmpty()) {
            headers.forEach(builder::setHeader);
        }
        Message<?> message = builder.build();

        // 发送消息
        return rocketMQTemplate.syncSend(topic, message, timeout);
    }

    // ============================ 延迟同步发送（定时投递）============================

    /**
     * 延迟同步发送（按 RocketMQ 原生延迟级别）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param delayLevel 延迟级别（1-18，对应：1s/5s/10s/30s/1m/2m/3m/4m/5m/6m/7m/8m/9m/10m/20m/30m/1h/2h）
     * @return 发送结果
     */
    public SendResult syncSendDelay(String topic, Object payload, int delayLevel) {
        return syncSendDelay(topic, payload, delayLevel, 3000L);
    }

    /**
     * 延迟同步发送（自定义超时时间）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param delayLevel 延迟级别（1-18）
     * @param timeout 发送超时时间（毫秒）
     * @return 发送结果
     */
    public SendResult syncSendDelay(String topic, Object payload, int delayLevel, long timeout) {
        Assert.hasText(topic, "消息主题（topic）不能为空");
        Assert.notNull(payload, "消息内容（payload）不能为空");
        Assert.isTrue(delayLevel >= 1 && delayLevel <= 18, "延迟级别必须在 1-18 之间");

        Message<?> message = MessageBuilder.withPayload(payload).build();
        return rocketMQTemplate.syncSend(topic, message, timeout, delayLevel);
    }

    // ============================ 顺序同步发送（保证同一逻辑流顺序）============================

    /**
     * 顺序同步发送（单条消息，按 hashKey 路由到同一队列）
     * 场景：订单支付、物流轨迹等需要严格顺序的消息
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param hashKey 路由键（必填，如：订单ID、用户ID，确保同一键的消息进入同一队列）
     * @return 发送结果
     */
    public SendResult syncSendOrderly(String topic, Object payload, String hashKey) {
        return syncSendOrderly(topic, payload, hashKey, 3000L);
    }

    /**
     * 顺序同步发送（自定义超时时间）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param hashKey 路由键（必填）
     * @param timeout 发送超时时间（毫秒）
     * @return 发送结果
     */
    public SendResult syncSendOrderly(String topic, Object payload, String hashKey, long timeout) {
        Assert.hasText(topic, "消息主题（topic）不能为空");
        Assert.notNull(payload, "消息内容（payload）不能为空");
        Assert.hasText(hashKey, "顺序路由键（hashKey）不能为空");

        return rocketMQTemplate.syncSendOrderly(topic, payload, hashKey, timeout);
    }

    // ============================ 异步发送（非阻塞，回调通知结果）============================

    /**
     * 异步发送（单条消息，默认超时时间）
     * 场景：无需等待发送结果，但需要知道是否成功（如：日志上报、非核心通知）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param callback 发送回调（成功/失败回调处理）
     */
    public void asyncSend(String topic, Object payload, SendCallback callback) {
        asyncSend(topic, payload, callback, 3000L);
    }

    /**
     * 异步发送（自定义超时时间）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     * @param callback 发送回调（必填，处理成功/失败逻辑）
     * @param timeout 发送超时时间（毫秒）
     */
    public void asyncSend(String topic, Object payload, SendCallback callback, long timeout) {
        Assert.hasText(topic, "消息主题（topic）不能为空");
        Assert.notNull(payload, "消息内容（payload）不能为空");
        Assert.notNull(callback, "发送回调（SendCallback）不能为空");

        Message<?> message = MessageBuilder.withPayload(payload).build();
        rocketMQTemplate.asyncSend(topic, message, callback, timeout);
    }

    // ============================ 单向发送（无回调、无确认，最快）============================

    /**
     * 单向发送（单条消息，无结果反馈）
     * 场景：不需要确认发送结果，追求最高性能（如：日志打印、心跳包）
     * @param topic 消息主题（必填）
     * @param payload 消息内容（必填）
     */
    public void sendOneWay(String topic, Object payload) {
        Assert.hasText(topic, "消息主题（topic）不能为空");
        Assert.notNull(payload, "消息内容（payload）不能为空");

        rocketMQTemplate.sendOneWay(topic, payload);
    }
}
